import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt
import statsmodels.api as sm
from preprocessing import preprocess_data

# 设置支持中文的字体
plt.rcParams["font.sans-serif"] = ["Songti SC"]
plt.rcParams["axes.unicode_minus"] = False

def calculate_woe_iv(df, feature, target):
    """计算单个特征的WOE和IV值"""
    # 计算每个分箱的坏样本数和好样本数
    df_woe = df.groupby(feature)[target].agg(['count', 'sum'])
    df_woe.columns = ['total', 'bad']
    df_woe['good'] = df_woe['total'] - df_woe['bad']
    
    # 计算坏样本和好样本的总数
    total_bad = df_woe['bad'].sum()
    total_good = df_woe['good'].sum()
    
    # 计算每个分箱的坏样本和好样本占比
    df_woe['bad_rate'] = df_woe['bad'] / total_bad
    df_woe['good_rate'] = df_woe['good'] / total_good
    
    # 计算WOE和IV
    df_woe['woe'] = np.log(df_woe['bad_rate'] + 0.5 / df_woe['good_rate'] + 0.5)
    df_woe['iv'] = (df_woe['bad_rate'] - df_woe['good_rate']) * df_woe['woe']
    
    # 计算总IV值
    iv_total = df_woe['iv'].sum()
    
    return df_woe, iv_total

def build_scorecard_model(data_path, iv_threshold=0.1):
    """构建评分卡模型"""
    # 读取数据
    df = pd.read_excel(data_path)
    
    # 预处理数据
    df = preprocess_data(data_path, include_renewal=True)
    
    # 计算每个特征的IV值
    iv_results = {}
    features = df.drop(['policy_id', 'renewal', 'policy_start_date', 'policy_end_date'], axis=1).columns
    
    for feature in features:
        _, iv = calculate_woe_iv(df, feature, 'renewal')
        iv_results[feature] = iv
    
    # 筛选IV>=0.1的特征
    selected_features = [f for f, iv in iv_results.items() if iv >= iv_threshold]
    print(f"筛选后的特征: {selected_features}")
    
    # 准备建模数据
    X = df[selected_features]
    y = df['renewal']
    
    # 使用逻辑回归建模
    model = LogisticRegression()
    model.fit(X, y)
    
    # 输出模型系数
    coef = pd.DataFrame({
        'feature': selected_features,
        'coefficient': model.coef_[0]
    })
    
    # 计算评分卡分数
    scorecard = coef.copy()
    scorecard['score'] = scorecard['coefficient'] * 100  # 简单线性转换
    
    # 生成Markdown格式的评分计算说明
    with open("data/scorecard_instructions.md", "w") as f:
        f.write("# 寿险续保评分卡使用说明\n\n")
        f.write("## 评分计算方法\n\n")
        f.write("1. 基础分: 600分 (可根据业务需求调整)\n")
        f.write("2. 特征得分计算:\n")
        
        # 获取原始数据以显示特征值范围
        raw_df = pd.read_excel(data_path)
        raw_df = preprocess_data(data_path, include_renewal=True)
        
        for _, row in scorecard.iterrows():
            feature = row['feature']
            f.write(f"   - {feature}: 每单位变化 {row['score']:.2f}分\n")
        
        f.write("\n3. 总分计算公式:\n")
        f.write("   ```\n")
        f.write("   总分 = 基础分 + 特征1得分 + 特征2得分 + ... + 特征N得分\n")
        f.write("   ```\n\n")
        f.write("## 示例计算\n\n")
        # 随机选取一个客户作为示例
        example_customer = raw_df.sample(1).iloc[0]
        
        f.write("假设某客户有以下特征值:\n")
        for _, row in scorecard.iterrows():
            feature = row['feature']
            value = example_customer[feature]
            f.write(f"- {feature}: {value:.2f}\n")
        f.write("\n则其得分为:\n")
        f.write("```\n")
        f.write("总分 = 600")
        for _, row in scorecard.iterrows():
            f.write(f" + {row['score']:.2f}")
        f.write("\n```\n")
    
    print("\n评分计算说明已保存到 data/scorecard_instructions.md")
    
    return model, scorecard

def calculate_scores(data_path, scorecard_rules):
    """计算所有客户的评分并保存到CSV"""
    # 读取数据
    df = pd.read_excel(data_path)
    
    # 预处理数据
    df = preprocess_data(data_path, include_renewal=True)
    
    # 计算每个客户的得分
    base_score = 600
    df['score'] = base_score
    
    for _, rule in scorecard_rules.iterrows():
        feature = rule['feature']
        score = rule['score']
        df['score'] += df[feature] * score
    
    # 保存结果
    output_path = "data/customer_scores.csv"
    df[['policy_id', 'score']].to_csv(output_path, index=False)
    print(f"客户评分已保存到 {output_path}")
    
    return df

def plot_score_distribution(scores_file="data/customer_scores.csv"):
    """绘制客户评分分布图"""
    # 读取评分数据
    df = pd.read_csv(scores_file)
    
    # 创建图表
    plt.figure(figsize=(10, 6))
    plt.hist(df['score'], bins=20, edgecolor='black')
    plt.title('客户评分分布')
    plt.xlabel('评分')
    plt.ylabel('客户数量')
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # 保存图表
    plt.savefig("data/score_distribution.png")
    plt.close()
    print(f"评分分布图已保存到 data/score_distribution.png")

if __name__ == "__main__":
    # 构建评分卡模型
    model, scorecard = build_scorecard_model("data/policy_data.xlsx")
    
    # 保存评分卡规则
    scorecard.to_csv("data/scorecard_rules.csv", index=False)
    
    # 计算所有客户评分
    calculate_scores("data/policy_data.xlsx", scorecard)
    
    # 绘制评分分布图
    plot_score_distribution()